import UIKit

/* XCode15的Swift版本5.9 */

/* Swift面向对象 */
// 基类
// Swift中不是所有的类都是从一个通用的类继承而来的
// 没有父类的类就就是基类
class Student {
    var name = ""
    var age = 0
    var id = ""
    var basicInfo: String {
        return "\(name) is \(age) years old, the id is \(id)"
    }
    func chooseClass(){
        print("\(name) choose a class.")
    }
    func haveClass(){
        print("\(name) have a class.")
    }
    // 构造器
    // 可以构造多个参数类型不同的构造器
    // 具体使用的构造器根据传入的参数类型自动选择
    
    // 类是引用类型
    // 引用类型的构造器有两种
    // 一种是指定构造器（纵向代理）
    // 指定构造器必须调用其直接父类的指定构造器
    // 指定构造器要实现为所有的应当赋值的属性赋值
    // 一种是便利构造器（横向代理）
    // 便利构造器必须调用同一个类中的其他构造器（包括便利构造器）
    // 便利构造器链必须最终调用一个指定构造器

    // 指定构造器
    init(){
        name = "no name"
        age = 16
        id = "no id"
    }
    // 便利构造器
    convenience init(name : String, age : Int){
        self.init()
        self.name = name
        self.age = age
    }
    convenience init(name : String, age : Int, id : String){
        // 调用指定构造器必须在一开始进行，否则会报错找不到self
        self.init()
        self.name = name
        self.age = age
        self.id = id
    }
    // 析构器
    deinit {
        print("call deinit of Class Student")
    }
}

let theStudent = Student()
theStudent.name = "Tommy"
theStudent.age = 19
theStudent.id = "37060115"
print(theStudent.basicInfo)

// 继承
// 见learn_6
// 子类只能有一个父类（单继承）
// 类的继承深度没有限制
class Graduate : Student {
    var supervisor: String
    override var age: Int {
        didSet {
            print("age is set from \(oldValue) to \(age)")
        }
        willSet {
            print("original age will be set to \(newValue)")
        }
    }
    var researchTopic: String
    override var basicInfo: String {
        return super.basicInfo + ", supervisor is \(supervisor), research topic is \(researchTopic)"
    }
    func chooseSuperVisor(superVisor: String){
        self.supervisor = superVisor
    }
    // 重载方法
    override func chooseClass () {
        print ("graduate \(name) choose a class")
    }
    //  子类是不会自动继承父类构造器的，而需要使用关键字override来重载父类构造器。除非子类中没有提供任何指定构造器
    override init(){
        supervisor = ""
        researchTopic = ""
        super.init()
    }
    convenience init(name: String, age: Int, id: String, supervisor: String, researchTopic: String) {
        // 调用的是经过了重写之后实现继承的父类的convenience init
        self.init(name: name, age: age, id: id)
        self.supervisor = supervisor
        self.researchTopic = researchTopic
    }
    deinit {
        print("call deinit of Class Graducate")
    }
}

let theGraduate = Graduate()
theGraduate.name = "Sam"
theGraduate.age = 23
theGraduate.id = "SY0602115"
// 调用的是重载方法
theGraduate.haveClass()
theGraduate.researchTopic = "Graphics"
theGraduate.chooseSuperVisor(superVisor: "Ian")
print(theGraduate.basicInfo)

print ("Graduate \(theGraduate.name) is \(theGraduate.age) and the id is \(theGraduate.id), The research topic is \(theGraduate.researchTopic) and supervisor is \(theGraduate.supervisor)")

class Doctor: Graduate {
    var articles = [String]()
    func publishArticle(article: String){
        articles.append(article)
    }
}

let theDoctor = Doctor()
theDoctor.name = "Pennie"
theDoctor.age = 26
theDoctor.id = "BY0607120"
print(theDoctor.basicInfo)
theDoctor.chooseSuperVisor(superVisor: "Ellis")
print(theDoctor.supervisor)
theDoctor.publishArticle(article: "Petri nets theory")
theDoctor.publishArticle(article: "Process management")
print(theDoctor.articles)

// 多态
func sportsGameRoster(student: Student) -> String {
    return "Athlete name: \(student.name), age: \(student.age), id: \(student.id)"
}

let studentTom = Student ()
studentTom.name = "Tom"; studentTom.age = 19; studentTom.id = "37060116"
let graduateJim = Graduate()
graduateJim.name = "Jim"; graduateJim.age = 24; graduateJim.id = "SY060218"

let rosterTom = sportsGameRoster(student: studentTom)
// 此时graduateJim表现为Student类的实例
let rosterJim = sportsGameRoster(student: graduateJim)

// 重载
// 重载方法
// 见上方Graduate

// 重载属性
// 见上方Graduate
// 被重载的属性要与父类同名同类型
// 目的是提供新的get和set方法、添加新的观察器
// 可以将只读的属性通过增加set方法更改为读写属性，不可以将读写属性重载为只读属性
// 不能为继承来的常量存储属性或只读的属性增加属性观察器

// 禁止重载
// 添加final
// 父类的方法、属性以及下标，都可以通过在前面加上关键字final来禁止子类重载

// 禁止继承
// 如果要禁止一个类被继承，也可以在类定义前加上final关键字 来禁止该类被继承

// 构造器
// 在类的定义中，如果属性的值有可能为空，必须要声明为可选型
// 对于可选型的属性，系统会自动为该属性初始化为nil，不需要在构造器里进行初始化
// 常量的初始化必须在构造器中完成

// 构造器代理
// 定义复杂的构造器的时候，可以调用已知的构造器来完成部分构造工作

// 结构体当中的构造器代理
struct structStudent {
    var name : String
    var age: Int
    var id: String
    var basicInfo : String {
        return "\(name) is \(age) years old, the id is \(id)"
    }
    init(){
        name = "no name"
        age = 16
        id = ""
    }
    init(name : String, age : Int){
        self.name = name
        self.age = age
        self.id = ""
    }
    init(name: String, age: Int, id : String){
        // 调用其他的构造器
        self.init (name : name, age : age)
        self.id = id
    }
}

let theStructStudent = structStudent(name: "Sam", age: 28, id: "BY0601115")

// 类当中的构造器代理
// 见上方Student和上方Graduate

// 析构器
// 只有引用类型的类才有析构器
// 每个类最多只能有一个析构器
var varGraduate: Graduate? = Graduate()
varGraduate = nil
// 子类会自动继承父类的析构器
// 在子类析构器实现的最后，父类的析构器会被自动调用
